package android.slc.appbase.api.slc.utils

import cn.hutool.core.lang.Validator
import cn.hutool.core.util.ReUtil
import cn.hutool.core.util.StrUtil

/**
 * ip地址遍历工具
 * @Description:
 * @Author: sunlunchang
 * @CreateDate: 2022/06/30 下午 4:05
 *
 */
class IpReckonUtils {
    //ip地址的部件
    private val ipParts = mutableListOf<Int>()

    //ip地址遍历依据
    private var ipGist: String? = null

    //ip地址遍历依据是否有效
    private var gistEffective = false

    //只遍历最后一个节点
    private var onlyLastSit = true

    /**
     * 设置ip地址的依据
     */
    fun setIpGist(ipGist: String, startSite: Int?) {
        this.gistEffective = ReUtil.isMatch(Validator.IPV4, ipGist)
        if (this.gistEffective) {
            startSite?.let {
                if (startSite < 1 || startSite >= 255) {
                    throw RuntimeException("must:startSite > 0 && startSite < 255")
                }
            }
            val ipPartsTemp: List<String> = ipGist.split(StrUtil.C_DOT)
            this.ipParts.clear()
            this.ipParts.add(ipPartsTemp[0].toInt())
            this.ipParts.add(ipPartsTemp[1].toInt())
            this.ipParts.add(ipPartsTemp[2].toInt())
            this.ipParts.add(ipPartsTemp[3].toInt())
            startSite?.let {
                this.ipParts[3] = startSite - 1
            }
            this.ipGist = ipGist
        }
    }

    /**
     * 设置是否只遍历最后一个
     */
    fun setOnlyLastSit(onlyLastSit: Boolean) {
        this.onlyLastSit = onlyLastSit
    }

    /**
     * 是否存在下一个
     */
    fun hasNext(): Boolean {
        if (!this.gistEffective) {
            return false
        }
        return checkIpPartStartEndNextLegal(this.ipParts[3])
                || (!this.onlyLastSit && checkIpPartStartEndNextLegal(this.ipParts[0]))
    }

    /**
     * 获取下一个地址
     */
    fun next(): String {
        assertHasNext()
        if (this.onlyLastSit) {
            partAutoIncrement(3)
        } else {
            var result = partAutoIncrement(3)
            if (!result) {
                result = partAutoIncrement(2)
            }
            if (!result) {
                result = partAutoIncrement(1)
            }
            if (!result) {
                partAutoIncrement(0)
            }
        }
        val nextIp = ipParts.joinToString(separator = StrUtil.C_DOT.toString())
        return nextIp
    }

    /**
     * 检查ip地址部件开始和结束位置下一个是否合法
     */
    private fun checkIpPartStartEndNextLegal(ipPart: Int): Boolean {
        return ipPart + 1 in 1..254
    }

    private fun checkIpPartRuleNextLegal(ipPart: Int): Boolean {
        return ipPart + 1 in 0..254
    }

    /**
     * 自增1
     */
    private fun partAutoIncrement(indexPart: Int): Boolean {
        //1、检查是否存在下一个
        //2、判断位置
        //3、检查下一个是否合法，不合法则设置为相应初始值
        //4、检查下一个是否合法，合法则自增1
        assertHasNext()
        var result = false
        when (indexPart) {
            0, 3 -> {
                result = checkIpPartStartEndNextLegal(this.ipParts[indexPart])
                if (!result) {
                    //此处如果ip部件下标为0的话不应该置为1，但是此情况永远不会在此处发生，因为上面执行hasNext时已经检查过了
                    this.ipParts[indexPart] = 1
                }
            }
            1, 2 -> {
                result = checkIpPartRuleNextLegal(this.ipParts[indexPart])
                if (!result) {
                    //此处如果ip部件下标为0的话不应该置为1，但是此情况永远不会在此处发生，因为上面执行hasNext时已经检查过了
                    this.ipParts[indexPart] = 0
                }
            }
        }
        if (result) {
            this.ipParts[indexPart] = this.ipParts[indexPart] + 1
        }
        return result
    }

    private fun assertHasNext() {
        if (!hasNext()) {
            throw RuntimeException("there is no next one")
        }
    }
}